# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: Heater P-V.py
  @time: 2022/3/30 15:51
  @desc:
"""
import time

from math import *
from ATS.hardwarescan import conf_file_manager
from ATS.application.LCR_App.U2722A_App import U2722A_App
from ATS.application.LCR_App.B2901BL_App import B2901BLApp
from ATS.application.LASER_App.L8164B_App import L8164B_App
from ATS.application.LASER_App.N7744C_App import N7744C_App
from ATS.datamanager import data_transfer_station as DataTransferStation
from utils.read_ini_2_dict import get_option_value, get_refrence_data, get_loss_data
from utils.get_wave_power_util import get_wave_power_value, get_wave_loss_gc
from ATS.application.VNA_App.N5225B_App import N5225BApp
from ATS.util.calcu_step_util import get_points_list, get_step_list
from ATS.util.save_data_2_csv_util import saveData2CSV
from utils.find3db_util import find3db_util
from collections import namedtuple
from matplotlib import pyplot as plt
import numpy as np
from ATS.switchdriver.LightSwitchDriver import LightSwitchDriver
from utils.log_util import loggings
from gui.driver.var_manager import VarManager
from utils.save_setting_2_ini import save_ini_info
from gui import constant


# 通道1设置扫描电压，通道2、3固定电压
def er1_test(para):
    result_data = namedtuple("result_data", "subdie,test_item,curve_type,y_invert,test_result")
    try:
        total_time = 20
        inst_light = LightSwitchDriver.instance()
        if inst_light.is_connected:
            inst_light.set_all_switch("01", "05")
            time.sleep(1)
            loggings.info("switch" + str(inst_light.query_switch()))
        else:
            inst_light.connect()
        l8164 = para.l8164_setting
        n7744 = para.n7744_setting
        l8164b_app = L8164B_App(l8164["title"])
        n7744c_app = N7744C_App(n7744["title"])

        l8164b_app.set_power_unit()
        l8164b_app.set_power_value(float(l8164["power_value"]))
        l8164b_app.set_wave_length(int(l8164["wave_length"][0]))
        time.sleep(4)
        p_in = l8164b_app.fetch_input_power()
        l8164b_app.output_on()
        n7744c_app.reset()
        n7744c_app.set_power_wave_length()
        n7744c_app.set_power_unit()
        n7744c_app.set_power_range_auto()
        n7744c_app.set_power_atim(n7744["atim"])

        time.sleep(5)

        smu_setting = para.smu_setting
        smu_dict = {}
        # smu voltage_list channel nplc current_range current_limit //mode sweep
        #
        spci_meas_list = []
        mes_plans_dict = {"var_func": None, "var1": None, "measure_func": None}
        init_set_list = []
        channel_close_list = []
        if smu_setting:
            for smu in smu_setting:
                if smu["smu"] == "SMU10":
                    b2901 = B2901BLApp(smu["smu"])
                    bias_voltage = smu["voltage_list"][0]
                    b2901.spot_setting(bias_voltage, smu["current_limit"])
                    break
                if smu["smu"] not in smu_dict:
                    smu_dict[smu["smu"]] = U2722A_App(smu["smu"])
                current_inst = smu_dict[smu["smu"]]
                current_voltage_list = smu["voltage_list"]
                current_channel = smu["channel"]
                current_channel_nplc = smu["nplc"]
                current_channel_range = smu["current_range"]
                current_channel_limit = smu["current_limit"]
                init_set_list += [lambda y=current_channel,
                                         inst_obj=current_inst: inst_obj.output_state(0, y),
                                  lambda x=current_channel, inst_obj=current_inst: inst_obj.set_voltage_range(x),
                                  lambda x=current_channel_nplc, y=current_channel,
                                         inst_obj=current_inst: inst_obj.set_current_nplc(x, y),
                                  lambda x=current_channel_range, y=current_channel_limit,
                                         z=current_channel, inst_obj=current_inst: inst_obj.set_current_range_limit(x,
                                                                                                                    y,
                                                                                                                    z)]
                if smu["mode"] == "sweep":
                    mes_plans_dict["var1"] = current_voltage_list
                    mes_plans_dict["var_func"] = lambda volt, x=current_channel, inst_obj=current_inst: \
                        inst_obj.set_voltage(volt, x)
                    mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                        float(inst_obj.get_current_value(x)))
                else:
                    init_set_list += [lambda x=current_voltage_list[0], y=current_channel,
                                             inst_obj=current_inst: inst_obj.set_voltage(x, y)]

                    spci_meas_list += [lambda x, y=current_channel, z=current_voltage_list[0],
                                              inst_obj=current_inst: inst_obj.set_voltage(
                        float(x) + float(z), y)]

                if smu["is_measure"]:
                    mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                        float(inst_obj.get_current_value(x)))

                init_set_list += [lambda y=current_channel,
                                         inst_obj=current_inst: inst_obj.output_state(1, y)]

                channel_close_list += [lambda y=current_channel,
                                              inst_obj=current_inst: inst_obj.output_state(0, y)]

            # set init
            for inst_set_func in init_set_list:
                inst_set_func()  # 设置SMU

            # read mes
            power_list = []
            mes_func = mes_plans_dict["measure_func"]
            if mes_func:  # mes func不为空
                if mes_plans_dict["var1"]:  # sweep
                    for volt in mes_plans_dict["var1"]:
                        mes_plans_dict["var_func"](volt)
                        power_value = n7744c_app.get_power_value()
                        power_list.append(float(power_value))
            sweep_list = [float(i) for i in mes_plans_dict["var1"]]

            wave_power_tuple = get_refrence_data()
            loss_section = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_name.split('_')[0]}_GC"
            loss_gc = get_wave_loss_gc(l8164["wave_length"][0], get_loss_data(section=loss_section))
            loss_sys = get_wave_power_value(l8164["wave_length"][0], wave_power_tuple)
            print("p_in", p_in)
            print("loss_sys", loss_sys)
            print("loss_gc", loss_gc)
            for num_index in range(len(power_list)):
                power_list[num_index] = round(
                    (float(p_in) - power_list[num_index] - float(loss_sys) - 2 * float(loss_gc)), 3)
            title_section = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_name}"
            # 寻找P-V曲线上的3db的电压值和IL值
            vppd_value = para.vppd
            datas = find3db_util(sweep_list, power_list)
            if datas and len(datas) == 4:
                # 设置bias电压
                half_slope_voltage = datas[0]
                if mes_plans_dict["var1"]:
                    mes_plans_dict["var_func"](half_slope_voltage)

                spci_meas_list[0](0.25 * float(vppd_value))
                b2901.set_voltage(-0.25 * float(vppd_value) + float(bias_voltage))
                p1_list = []
                for i in range(total_time):
                    p1 = n7744c_app.get_power_value()
                    p1_list.append(float(p1))
                    time.sleep(0.1)
                min_p1 = min(p1_list)
                max_p1 = max(p1_list)

                p1_list.remove(min_p1)
                p1_list.remove(max_p1)

                p1 = sum(p1_list) / len(p1_list)

                # sweep_inst.set_voltage(2 - 0.25 * vppd, 2)
                # sweep_inst.set_voltage(2 + 0.25 * vppd, 3)
                spci_meas_list[0](-0.25 * float(vppd_value))
                b2901.set_voltage(0.25 * float(vppd_value) + + float(bias_voltage))

                p2_list = []
                for i in range(total_time):
                    p2 = n7744c_app.get_power_value()
                    p2_list.append(float(p2))
                    time.sleep(0.1)
                print("p2", p2_list)
                min_p2 = min(p2_list)
                max_p2 = max(p2_list)
                print("min_p1", min_p1)
                print("max_p1", max_p1)
                print("min_p2", min_p2)
                print("max_p2", max_p2)
                p2_list.remove(min_p2)
                p2_list.remove(max_p2)
                print("半坡电压", half_slope_voltage)
                print("p1_List", p1_list)
                print("p2_list", p2_list)
                p2 = sum(p2_list) / len(p2_list)
                print("p1", p1)
                print("p2", p2)

                er = abs(float(p1) - float(p2))
                print("er", er)
                save_ini_info(constant.REMEMBER_VALUE, "remember_value", f"{title_section}_ER1",
                              str(er))
            else:
                print("No Value")
            for channel_close in channel_close_list:
                channel_close()
            b2901.output_close()

    except Exception as e:
        loggings.error("er1_test" + str(e))
    finally:
        close_all_channel()


def close_all_channel():
    U2722A_App("SMU2").close_all_channel()
    U2722A_App("SMU3").close_all_channel()
    U2722A_App("SMU4").close_all_channel()
    B2901BLApp("SMU10").output_close()


def plot_curve2(curve_list, title, x, y, max_x, max_y):
    color = ["r", "m", "c", "y"]
    label = ["0s", "60s", "300s", "10s"]
    plt.figure(figsize=(20, 20), dpi=100)
    fig, ax = plt.subplots()
    ax.set_title(f"{title} P-V curve")
    for i in range(len(curve_list)):
        ax.plot(curve_list[i][0], curve_list[i][1], color[i], label=f"{label[i]}")
        ax.plot([max_x], [max_y], "s")
        ax.text(max_x, max_y, f"{str(max_x)},{str(max_y)}")
        ax.plot([x], [y], "s")
        ax.text(x, y, f"{str(x)},{str(y)}")
        ax.set_xlabel("Voltage")
        ax.set_ylabel("Power")
        ax.grid(True)
        ax.legend()
    plt.savefig(f"{title}.png")
    plt.show()


def plot_curve(curve_list):
    plt.figure(figsize=(20, 20), dpi=100)
    fig, ax = plt.subplots()
    ax.plot(curve_list[0], curve_list[1], "y")
    ax.grid(True)
    plt.show()


er1_test(locals()['para'])
